library(readxl)
mydata <- read_xlsx("./Proteins.xlsx")
mydata <- as.data.frame(mydata)
head(mydata, 3)
##   Country Alcohol Cereals   Eggs   Fish Fruits    Meat Pulses Spices
## 1 Albania  0.1840 14.2331 1.8069 0.6274 1.2757  7.6582 1.4555 0.0000
## 2 Austria  0.6150 13.1508 2.1456 1.8358 0.6242 13.6549 0.2405 0.1341
## 3 Belarus  0.3401 13.7248 2.2901 2.4548 0.4410 14.2402 0.0053 0.0213
##   Treenuts Vegetables
## 1   0.2677     3.2456
## 2   0.3561     1.5259
## 3   0.3454     2.8587

Description:

mydata_PCA <- mydata[c(2:11)] 
rownames(mydata_PCA) <- mydata$Country

desc_stats <- data.frame(
  N        = apply(mydata_PCA, 2, function(x) sum(!is.na(x))),
  Missing  = apply(mydata_PCA, 2, function(x) sum(is.na(x))),
  Mean     = colMeans(mydata_PCA, na.rm = TRUE),
  Variance = apply(mydata_PCA, 2, var, na.rm = TRUE),
  Min      = apply(mydata_PCA, 2, min, na.rm = TRUE),
  Max      = apply(mydata_PCA, 2, max, na.rm = TRUE)
)

round(desc_stats, 2)
##             N Missing  Mean Variance  Min   Max
## Alcohol    38       0  0.46     0.04 0.16  1.17
## Cereals    38       0 14.23     6.87 9.38 20.47
## Eggs       38       0  1.73     0.22 0.79  3.09
## Fish       38       0  3.03     3.36 0.63  9.40
## Fruits     38       0  0.68     0.04 0.39  1.28
## Meat       38       0 12.17     5.11 6.71 15.73
## Pulses     38       0  0.81     0.30 0.01  2.28
## Spices     38       0  0.14     0.05 0.00  1.35
## Treenuts   38       0  0.35     0.04 0.03  0.89
## Vegetables 38       0  1.99     0.60 0.98  4.37
R <- cor(mydata_PCA)

library(GGally)

ggpairs(
  mydata_PCA,
  upper = list(continuous = wrap("points", size = 1)),
  lower = list(continuous = wrap("cor", size = 2.5), colour = "black"),
  diag = list(continuous = wrap("densityDiag", size = 0.6))
) +
  theme(
    axis.text.x = element_text(size = 5),
    axis.text.y = element_text(size = 5),
    strip.text.x = element_text(size = 6),
    strip.text.y = element_text(size = 4),
    axis.title = element_blank())
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the GGally package.
##   Please report the issue at
##   <https://github.com/ggobi/ggally/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning
## was generated.

# Convert correlation matrix to a distance matrix
dist_vars <- as.dist(1 - abs(R))

# Hierarchical clustering of variables
hc_vars <- hclust(dist_vars, method = "average")

# Reorder the correlation matrix according to the clustering
R_reordered <- R[hc_vars$order, hc_vars$order]

library(GGally)
ggpairs(R_reordered,
  upper = list(continuous = wrap("points", size = 1)),
  lower = list(continuous = wrap("cor", size = 2.5), colour = "black"),
  diag = list(continuous = wrap("densityDiag", size = 0.6))) +
  theme(axis.text.x = element_text(size = 5),
        axis.text.y = element_text(size = 5),
        strip.text.x = element_text(size = 6),
        strip.text.y = element_text(size = 5),
        axis.title = element_blank())

library(psych)
cortest.bartlett(R, n = nrow(mydata_PCA)) 
## $chisq
## [1] 107.6373
## 
## $p.value
## [1] 4.766781e-07
## 
## $df
## [1] 45
det(R) 
## [1] 0.03769258
library(psych)
KMO(R) 
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = R)
## Overall MSA =  0.6
## MSA for each item = 
##    Alcohol    Cereals       Eggs       Fish     Fruits       Meat 
##       0.41       0.55       0.44       0.46       0.50       0.80 
##     Pulses     Spices   Treenuts Vegetables 
##       0.84       0.65       0.64       0.78
library(FactoMineR) 
components <- PCA(mydata_PCA, 
                  scale.unit = TRUE,
                  graph = FALSE) 

library(factoextra) 
get_eigenvalue(components) 
##       eigenvalue variance.percent cumulative.variance.percent
## Dim.1  3.1121916        31.121916                    31.12192
## Dim.2  1.9695156        19.695156                    50.81707
## Dim.3  1.1420515        11.420515                    62.23759
## Dim.4  0.9863102         9.863102                    72.10069
## Dim.5  0.6493707         6.493707                    78.59440
library(factoextra)
fviz_eig(components,
         choice = "eigenvalue",
         main = "Scree plot",
         ylab = "Eigenvalue",
         xlab = "Principal component",
         addlabels = TRUE)
## Warning: This FactoMineR PCA result contains only 5 eigenvalues and
## does not include the complete spectrum. Refit the PCA with a larger
## `ncp` before drawing a complete scree plot.

library(psych)
fa.parallel(
  mydata_PCA,
  fa         = "pc",
  cor        = "cor",
  n.iter     = 1000,
  sim        = TRUE,
  error.bars = TRUE
)

## Parallel analysis suggests that the number of factors =  NA  and the number of components =  2
library(FactoMineR)
components <- PCA(mydata_PCA, 
                  scale.unit = TRUE, 
                  graph = FALSE,
                  ncp = 2) 

components
## **Results for the Principal Component Analysis (PCA)**
## The analysis was performed on 38 individuals, described by 10 variables
## *The results are available in the following objects:
## 
##    name               description                          
## 1  "$eig"             "eigenvalues"                        
## 2  "$var"             "results for the variables"          
## 3  "$var$coord"       "coord. for the variables"           
## 4  "$var$cor"         "correlations variables - dimensions"
## 5  "$var$cos2"        "cos2 for the variables"             
## 6  "$var$contrib"     "contributions of the variables"     
## 7  "$ind"             "results for the individuals"        
## 8  "$ind$coord"       "coord. for the individuals"         
## 9  "$ind$cos2"        "cos2 for the individuals"           
## 10 "$ind$contrib"     "contributions of the individuals"   
## 11 "$call"            "summary statistics"                 
## 12 "$call$centre"     "mean of the variables"              
## 13 "$call$ecart.type" "standard error of the variables"    
## 14 "$call$row.w"      "weights for the individuals"        
## 15 "$call$col.w"      "weights for the variables"
print(components$var$cor) 
##                  Dim.1       Dim.2
## Alcohol    -0.28418398 -0.62609438
## Cereals     0.70595796 -0.41718411
## Eggs       -0.36437452 -0.34783780
## Fish       -0.55347719  0.47844021
## Fruits      0.38926370  0.68325045
## Meat       -0.74337993  0.03609410
## Pulses      0.57773132  0.36995101
## Spices      0.66082334 -0.24100811
## Treenuts   -0.02573995  0.62422247
## Vegetables  0.78656544 -0.02909236
print(components$var$contrib) 
##                 Dim.1       Dim.2
## Alcohol     2.5949731 19.90307538
## Cereals    16.0136874  8.83682173
## Eggs        4.2660865  6.14319236
## Fish        9.8431277 11.62240247
## Fruits      4.8687949 23.70284231
## Meat       17.7564172  0.06614744
## Pulses     10.7247085  6.94910716
## Spices     14.0315105  2.94919779
## Treenuts    0.0212887 19.78424008
## Vegetables 19.8794054  0.04297328
library(factoextra)
fviz_pca_var(components, 
             repel = TRUE)

library(factoextra)
fviz_pca_biplot(components,
                repel = TRUE) 

library(factoextra)

fviz_pca_biplot(
  components,
  geom.ind = c("point", "text"),
  geom.var = c("arrow", "text"),
  label = "all",
  repel = TRUE,
  col.ind = "black",
  col.var = "darkgreen",
  pointsize = 1,
  labelsize = 4,
  alpha.ind = 1,
  title = "PCA biplot") +
  theme_minimal(base_size = 14)

library(factoextra)
library(ggrepel)
library(ggplot2)


ind <- as.data.frame(get_pca_ind(components)$coord)[, 1:2]
vr  <- as.data.frame(get_pca_var(components)$coord)[, 1:2]
names(ind) <- c("x", "y"); ind$name <- rownames(ind)
names(vr)  <- c("x", "y"); vr$name  <- rownames(vr)

var_pct <- function(res) {
  ev <- try(factoextra::get_eigenvalue(res), silent = TRUE)
  if (!inherits(ev, "try-error") && !is.null(ev)) {
    if (is.data.frame(ev) || is.matrix(ev)) {
      j <- grep("variance.percent|percentage of variance|^variance",
                colnames(ev), ignore.case = TRUE)
      if (length(j)) return(as.numeric(ev[, j[1]]))
      return(100 * as.numeric(ev[, 1]) / sum(as.numeric(ev[, 1])))
    }
    if (is.numeric(ev)) return(100 * ev / sum(ev))          # <- tvoj primer
  }
  if (!is.null(res$sdev)) return(100 * res$sdev^2 / sum(res$sdev^2))   # prcomp / princomp
  if (!is.null(res$eig)) { e <- if (is.matrix(res$eig)) res$eig[, 1] else res$eig
                           return(100 * e / sum(e)) }                  # FactoMineR / ade4
  if (!is.null(res$Vaccounted)) return(100 * res$Vaccounted["Proportion Var", ])  # psych
  if (!is.null(res$values)) return(100 * res$values / sum(res$values))
  rep(NA_real_, 2)
}
pv  <- var_pct(components)
lab <- function(i) if (is.na(pv[i])) paste0("PC", i) else sprintf("PC%d (%.1f %%)", i, pv[i])

## --- 2. skupni faktor za pusice (ohrani kote med vektorji) -----
sc <- 0.85 * min(max(abs(ind$x)) / max(abs(vr$x)),
                 max(abs(ind$y)) / max(abs(vr$y)))
vr$xend <- vr$x * sc
vr$yend <- vr$y * sc

nud <- 0.10                       # 10 % dolzine vektorja navzven


vr_layer <- rbind(
  data.frame(x = vr$xend, y = vr$yend, name = vr$name,
             nx = vr$xend * nud, ny = vr$yend * nud),
  data.frame(x = ind$x, y = ind$y, name = "", nx = 0, ny = 0))

ind_layer <- rbind(
  ind[, c("x", "y", "name")],
  data.frame(x = vr$xend * (1 + nud), y = vr$yend * (1 + nud), name = ""))
ind_layer$nx <- 0; ind_layer$ny <- 0


pop_var <- data.frame(name = c("Fruits", "Pulses"),
                      dx   = c( 0.35,     0.30),
                      dy   = c( 0.30,    -0.25))
i <- match(pop_var$name, vr_layer$name)
vr_layer$nx[i] <- vr_layer$nx[i] + pop_var$dx
vr_layer$ny[i] <- vr_layer$ny[i] + pop_var$dy



## --- 4. graf ---------------------------------------------------
p <- ggplot() +
  geom_hline(yintercept = 0, colour = "grey80", linewidth = 0.3) +
  geom_vline(xintercept = 0, colour = "grey80", linewidth = 0.3) +
  geom_point(data = ind, aes(x, y), shape = 16, colour = "grey60", size = 1.1) +
  # imena drzav: majhna, siva, z belo obrobo crk -> berljiva tudi cez mrezo
  geom_text_repel(data = ind_layer, aes(x, y, label = name),
                  nudge_x = ind_layer$nx, nudge_y = ind_layer$ny,
                  size = 2.6, colour = "grey10",
                  segment.colour = "grey70", segment.size = 0.2,
                  min.segment.length = 0.2,
                  box.padding = 0.2, point.padding = 0.25,
                  bg.colour = "white", bg.r = 0.12,
                  max.overlaps = Inf, seed = 1) +
  # spremenljivke: crne pusice
  geom_segment(data = vr, aes(x = 0, y = 0, xend = xend, yend = yend),
               arrow = arrow(length = unit(6, "pt"), type = "closed"),
               colour = "black", linewidth = 0.5) +
  # imena spremenljivk: manjsi krepki napis v belem okvircku, na konici pusice
  geom_label_repel(data = vr_layer, aes(x, y, label = name),
                   nudge_x = vr_layer$nx, nudge_y = vr_layer$ny,
                   fill = "white", colour = "black", fontface = "bold",
                   size = 3.1, label.size = 0.25,
                   label.padding = unit(0.15, "lines"), label.r = unit(0.08, "lines"),
                   box.padding = 0.2, point.padding = 0,
                   segment.colour = "black", segment.size = 0.3,
                   min.segment.length = 0,        # crta se narise vedno
                   force = 0.6, force_pull = 1.6, # oznaka ostane pri pusici
                   max.overlaps = Inf, seed = 3) +
  coord_equal(clip = "off") +
  scale_x_continuous(expand = expansion(mult = 0.08)) +
  scale_y_continuous(expand = expansion(mult = 0.08)) +
  labs(title = "PCA biplot",
       x = lab(1), y = lab(2)) +
  theme_minimal(base_size = 12) +
  theme(panel.grid.minor = element_blank(),
        panel.grid.major = element_line(colour = "grey93", linewidth = 0.3),
        plot.title = element_text(face = "bold"))

p

ggsave("pca_biplot.png", p, width = 8, height = 5, dpi = 600, bg = "white")